/*****************************************************************************
*
*  PROJECT:     SlipStream
*               (CSkybox - skybox class)
*  LICENSE:     GNU General Public License v3 - http://www.gnu.org/licenses/gpl.html

*  DEVELOPERS:  Philip Farquharson	<B00137077@studentmail.uws.ac.uk>
*				John Gray			<B00145524@studentmail.uws.ac.uk>		
*				Zohaib Bhatti		<B00104280@studentmail.uws.ac.uk>
*				Euan Hislop			<B00138636@studentmail.uws.ac.uk>
*
*****************************************************************************/
#include "CSkybox.h"

void CSkybox::render()
{
	// draw the skybox 
	const GLfloat fSkyDist = 50.0;
	const GLfloat fTex = 1.0f;
	glDisable(GL_DEPTH_TEST);

	glPushMatrix();

		glRotatef(CCamera::GetSingletonPtr()->getYRotation(), 0.0f, 1.0f, 0.0f); // Rotating the skybox with the camera on the y axis

		glEnable(GL_TEXTURE_CUBE_MAP_EXT);
		glBindTexture(GL_TEXTURE_CUBE_MAP_EXT, cubeMap);                        
		glBegin(GL_TRIANGLE_STRIP);

		//west
			glTexCoord3f(-fTex, -fTex , fTex);
			glVertex3f(-fSkyDist, -fSkyDist,  fSkyDist);
			glTexCoord3f(-fTex, fTex, fTex);
			glVertex3f(-fSkyDist, fSkyDist,  fSkyDist);
			glTexCoord3f(-fTex, -fTex, -fTex);
			glVertex3f(-fSkyDist, -fSkyDist, -fSkyDist);
			glTexCoord3f(-fTex, fTex,-fTex);
			glVertex3f(-fSkyDist, fSkyDist,  -fSkyDist);
		//north
			glTexCoord3f(fTex, -fTex,-fTex);
			glVertex3f(fSkyDist, -fSkyDist, -fSkyDist);
			glTexCoord3f(fTex, fTex,-fTex);
			glVertex3f(fSkyDist, fSkyDist, -fSkyDist);	
		//east
			glTexCoord3f( fTex, -fTex, fTex);
			glVertex3f( fSkyDist, -fSkyDist,  fSkyDist);
			glTexCoord3f( fTex, fTex, fTex);
			glVertex3f( fSkyDist, fSkyDist,  fSkyDist);
		//south
			glTexCoord3f( -fTex, -fTex, fTex);
			glVertex3f( -fSkyDist, -fSkyDist,  fSkyDist);
			glTexCoord3f( -fTex, fTex, fTex);
			glVertex3f( -fSkyDist, fSkyDist,  fSkyDist);
		glEnd();
		glBegin(GL_QUADS);	
		//up
			glTexCoord3f( -fTex, fTex, -fTex);
			glVertex3f( -fSkyDist, fSkyDist,  -fSkyDist);
			glTexCoord3f( -fTex, fTex, fTex);
			glVertex3f( -fSkyDist, fSkyDist,  fSkyDist);
			glTexCoord3f( fTex, fTex, fTex);
			glVertex3f( fSkyDist, fSkyDist,  fSkyDist);
			glTexCoord3f( fTex, fTex, -fTex);
			glVertex3f( fSkyDist, fSkyDist,  -fSkyDist);
		//down
			glTexCoord3f( fTex, -fTex, -fTex);
			glVertex3f( fSkyDist, -fSkyDist,  -fSkyDist);
			glTexCoord3f( fTex, -fTex, fTex);
			glVertex3f( fSkyDist, -fSkyDist,  fSkyDist);
			glTexCoord3f( -fTex, -fTex, fTex);
			glVertex3f( -fSkyDist, -fSkyDist,  fSkyDist);
			glTexCoord3f( -fTex, -fTex, -fTex);
			glVertex3f( -fSkyDist, -fSkyDist,  -fSkyDist);
		glEnd();
	glPopMatrix();

	glEnable(GL_DEPTH_TEST);
	glDisable(GL_TEXTURE_CUBE_MAP_EXT);
}

int CSkybox::loadGLTextures()
{
	// create gluint array and set the GL properties for top, bottom and the four sides
	static GLuint cubeFaces[6] = {
    GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT,
    GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT,
    GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT
	};

	// now load the cube map
	glEnable(GL_TEXTURE_CUBE_MAP_EXT);
	glGenTextures(1, &cubeMap);			// create the cubemap texture on gluint cubeMap

	// Sanity check for loading the textures and confirming they are correctly loaded
	glBindTexture(GL_TEXTURE_CUBE_MAP_EXT, cubeMap);
	bool success = true;
	if (!loadFace(cubeFaces[0],"textures/xpos.bmp"))
		success =  false;
	if (!loadFace(cubeFaces[1],"textures/xneg.bmp"))
		success =  false;
	if (!loadFace(cubeFaces[2],"textures/ypos.bmp"))
		success =  false;
	if (!loadFace(cubeFaces[3],"textures/yneg.bmp"))
		success =  false;
	if (!loadFace(cubeFaces[4],"textures/zpos.bmp"))
		success =  false;
	if (!loadFace(cubeFaces[5],"textures/zneg.bmp"))
		success = false;
	if(!success)
	{
		MessageBox(NULL,"Cannot load Cube textures,", "Texture not found!",MB_OK);
		return	success;
	}

	glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glEnable(GL_TEXTURE_CUBE_MAP_EXT);

// updateTexgen
	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
	glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
// updateWrap
	glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

	glDisable(GL_TEXTURE_CUBE_MAP_EXT);
	return true;
}

bool CSkybox::loadFace(GLenum target, char *filename)
{
	// Load the skybox faces
	HBITMAP hBMP;														// Handle Of The Bitmap
	BITMAP	BMP;														// Bitmap Structure
	hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL), filename, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );

	char achError[200];

	GetObject(hBMP, sizeof(BMP), &BMP);									// Get The Object
																		// hBMP:        Handle To Graphics Object
																		// sizeof(BMP): Size Of Buffer For Object Information
																		// &BMP:        Buffer For Object Information

	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);								// Pixel Storage Mode (Word Alignment / 4 Bytes)
	
	glTexImage2D(target, 0, 3, BMP.bmWidth, BMP.bmHeight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);

	DeleteObject(hBMP);													// Delete The Object

	return true;
}

bool CSkybox::LoadBitmap(LPTSTR szFileName, GLuint &texid, GLuint target)					// Creates Texture From A Bitmap File
{
	HBITMAP hBMP;														// Handle Of The Bitmap
	BITMAP	BMP;														// Bitmap Structure
	glGenTextures(1, &texid);											// Create The Texture
	hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );

	char achError[200];

	GetObject(hBMP, sizeof(BMP), &BMP);									// Get The Object
																		// hBMP:        Handle To Graphics Object
																		// sizeof(BMP): Size Of Buffer For Object Information
																		// &BMP:        Buffer For Object Information

	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);								// Pixel Storage Mode (Word Alignment / 4 Bytes)
	
	// Typical Texture Generation Using Data From The Bitmap
	glBindTexture(target, texid);								// Bind To The Texture ID
	
	glTexImage2D(target, 0, 3, BMP.bmWidth, BMP.bmHeight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
	//glTexImage2D(target, 0, 3, BMP.bmWidth, BMP.bmHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, BMP.bmBits);
	glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);	// Linear Min Filter
	glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	// Linear Mag Filter
	//gluBuild2DMipmaps(target, 3, BMP.bmWidth, BMP.bmHeight, GL_RGB, GL_UNSIGNED_BYTE, BMP.bmBits); 
	gluBuild2DMipmaps(target, 3, BMP.bmWidth, BMP.bmHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits); 

	DeleteObject(hBMP);													// Delete The Object

	return TRUE;														// Loading Was Successful
}